package server

import (
	"fmt"
	"github.com/tealeg/xlsx"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"plan_go/config"
	"plan_go/dm"
	"plan_go/domain"
	"plan_go/server/util"
	"strings"
	"sync"
	"time"
)

var (
	bind = make(map[interface{}]bool)
)

func Execute(OrderXlsPath string) {
	// 打开XLSX文件
	xlFile, err := xlsx.OpenFile(OrderXlsPath)
	if err != nil {
		log.Fatal(err)
	}
	sheetName := "Sheet1"
	sheet := xlFile.Sheet[sheetName]
	// 遍历工作表中的行
	for j, row := range sheet.Rows {
		if 0 == j {
			continue
		}
		// 遍历行中的单元格
		var Order domain.Order
		var window domain.WindowInfo
		var endStr string
		for i, cell := range row.Cells {
			if 0 == i {
				endStr = cell.String()
				config.ParseJSON(cell.String(), &Order)
				log.Printf("Order: %v,", Order)
			}
			if 1 == i {
				config.ParseJSON(cell.String(), &window)
				log.Println("windowInfo: ", window)
			}
		}
		//空白行,已经结束,退出
		if "" == endStr {
			break
		}
		script := domain.Script{Order, window}
		explain(script)
	}
}

/**用于文件上传*/
func ExploreFileUpload(path string, windowInfo domain.WindowInfo) {
	time.Sleep(2 * time.Second)
	scripts := []domain.Script{
		domain.Script{
			Order:  domain.Order{Type: "resize", Resize: domain.Resize{X: 1226, Y: 930}},
			Window: windowInfo,
		},
		domain.Script{
			Order:  domain.Order{Type: "leftClick", Pos: domain.Position{X: 259, Y: 834}},
			Window: windowInfo,
		},
		domain.Script{
			Order:  domain.Order{Type: "sendString", Content: path},
			Window: windowInfo,
		},
		domain.Script{
			Order:  domain.Order{Type: "leftClick", Pos: domain.Position{X: 1051, Y: 867}},
			Window: windowInfo,
		},
		domain.Script{
			Order:  domain.Order{Type: "releaseHwnd"},
			Window: windowInfo,
		},
	}
	for _, script := range scripts {
		explain(script)
	}
	time.Sleep(1 * time.Second)
}

var hwndMap = make(map[string]*Hwnd)

type Hwnd struct {
	hwnd        int
	ClassName   string
	Title       string
	WindowOrder []int
	BindPara    domain.BindPara
	HasBindPre  *bool
	Dm          *dm.DmSoft
}

func GetHwnd(bindPara domain.WindowInfo) *Hwnd {
	name := bindPara.Class + bindPara.Title
	if nil != hwndMap[name] {
		return hwndMap[name]
	}
	getDm := dm.GetDm(name)
	hwnd := getDm.FindWindow(bindPara.Class, bindPara.Title)
	log.Println("GetHwnd hwnd句柄: ", hwnd)
	getDm.RegisterBindWindow(hwnd, bindPara.BindPara.Dx, bindPara.BindPara.Mouse, bindPara.BindPara.Keyboard, "", 0)
	time.Sleep(time.Second * 1)
	h := Hwnd{hwnd: hwnd, ClassName: bindPara.Class, Title: bindPara.Title, BindPara: bindPara.BindPara, Dm: getDm}
	hwndMap[name] = &h
	return &h
}
func (com Hwnd) ReleaseHwnd(bindPara domain.WindowInfo) {
	name := bindPara.Class + bindPara.Title
	hwndMap[name] = nil
}

func explain(script domain.Script) {
	hwnd := GetHwnd(script.Window)
	log.Printf("explain execute: %v,hwnd: %v", script, hwnd)
	switch script.Order.Type {
	case "leftClick":
		if "normal" == hwnd.BindPara.Mouse {
			hwnd.Dm.SetWindowState(hwnd.hwnd, 1)
			time.Sleep(200 * time.Microsecond)
		}
		hwnd.Dm.MoveAndLeftClick(script.Order.Pos.X, script.Order.Pos.Y)
		break
	case "sleep":
		time.Sleep(time.Millisecond * time.Duration(script.Order.Time))
		break
	case "keyPress":
		hwnd.Dm.KeyPress(script.Order.VkKey)
		break
	case "sendString":
		content := domain.SendStringMap[script.Order.Content]
		if "" == content {
			content = script.Order.Content
		}
		ret := hwnd.Dm.SendString(hwnd.hwnd, content)
		log.Println("sendString: ", ret)
		break
	case "resize":
		hwnd.Dm.SetWindowSize(hwnd.hwnd, script.Order.Resize.X, script.Order.Resize.Y)
		break
	case "releaseHwnd":
		hwnd.ReleaseHwnd(script.Window)
		break
	}
}

/**判断sovits是否已经加载过模型*/
var CheckSovitsModelHasLoad = false

/*
*
@description: 负责将音频中的干声替换音色
@param: audioPath 需要转换音频的绝对路径
*/
func SovitsConvert(audioPath string) {
	log.Println("SovitsConvert audioPath: ", audioPath)
	//检测所有必须软件是否已打开,未打开则打开,此步骤完成后会睡眠1.5秒
	CheckAllExeHasOpen()
	//获取audioPath的音频名
	originFileName := filepath.Base(audioPath)
	originFileNamePrefix := strings.Split(originFileName, ".")[0]
	//占位符提前赋值,用于执行uvr5 Excel中操作
	domain.SendStringMap["uvr5InputFileName"] = audioPath
	domain.SendStringMap["uvr5OutDirPath"] = config.GetConfig().OutPath
	//输出干声目录
	uvr5OutDirPath := domain.SendStringMap["uvr5OutDirPath"]
	//输出干声文件路径
	drySoundFileName := fmt.Sprintf(`%s\%s%s%s`, uvr5OutDirPath, "1_", originFileNamePrefix, "_(Vocals).wav")
	log.Println("drySoundFileName:", drySoundFileName)
	////uvr5剪辑干声操作
	Execute(config.GetPath("config/script.xlsx"))
	CheckUvr5HasStop(*GetHwnd(domain.WindowInfo{Class: "TkTopLevel", Title: "Ultimate Vocal Remover", BindPara: domain.BindPara{Dx: "dx2", Mouse: "normal", Keyboard: "windows"}}))

	////sovits操作
	chromeScript := ChromeScript{}
	//发放sovits转换任务
	taskChannel := make(chan TaskFunc, 1)
	if CheckSovitsModelHasLoad {
		log.Println("sovits模型已加载")
		taskChannel <- func() {
			chromeScript.ConvertSovitsAudioSecond(drySoundFileName)
			fmt.Println("Task 2 executed")
		}
	} else {
		taskChannel <- func() {
			chromeScript.ConvertSovitsAudioFirst(drySoundFileName)
			fmt.Println("Task 1 executed")
			CheckSovitsModelHasLoad = true
		}
	}
	chromeScript.ConvertSovitsAudioYouHua(taskChannel)
}

/**判断sovits是否已经加载过模型,暂时弃用*/
//func CheckSovitsModelHasLoad() bool {
//	ctx, _ := GetCtx()
//	var currentValue string
//	exitFlag := make(chan bool, 1)
//	go func() {
//		chromedp.Run(*ctx,
//			// 上传文件
//			chromedp.ActionFunc(func(ctx context.Context) error {
//				err := chromedp.Text(`#component-16 > label > div > div.wrap-inner.svelte-1ythexu > span`, &currentValue, chromedp.NodeVisible, chromedp.ByQuery)
//				log.Println("currentValue:", currentValue)
//				if err != nil || "ma" != currentValue {
//					exitFlag <- false
//				} else {
//					exitFlag <- true
//				}
//				return nil
//			}))
//	}()
//	return <-exitFlag
//}

func CheckAllExeHasOpen() {
	mainDm := dm.GetDm("main")
	wg := sync.WaitGroup{}
	wg.Add(2)

	go func() {
		uvr5Hwnd := mainDm.FindWindow("TkTopLevel", "Ultimate Vocal Remover")
		log.Println("uvr5Hwnd: ", uvr5Hwnd)
		if 0 == uvr5Hwnd {
			log.Println("uvr5未打开,自动打开uvr5")
			mainDm.RunApp(config.GetConfig().Uvr5Path, 0)
		}
		for {
			if 0 != uvr5Hwnd {
				log.Println("uvr5已打开,打开uvr5协程退出")
				time.Sleep(1500 * time.Microsecond)
				wg.Done()
				return
			}
			uvr5Hwnd = mainDm.FindWindow("TkTopLevel", "Ultimate Vocal Remover")
			time.Sleep(1 * time.Second)
		}
	}()
	go func() {
		ret := util.CheckUrl("http://localhost:7860", 2*time.Second)
		if false == ret {
			log.Println("sovits未打开,正在自动打开sovits")
			RunBat(config.GetConfig().SovitsPath)
		}
		for {
			if true == ret {
				log.Println("sovits已经打开,打开sovits协程退出")
				wg.Done()
				return
			}
			ret = util.CheckUrl("http://localhost:7860", 2*time.Second)
		}
	}()
	wg.Wait()
	log.Println("所有exe已经打开,检查工作完成")
}

func RunBat(path string) {
	go func() {
		//要写绝对路径  D:\51cto_course\51ctowkxz\51cto_video_download_20210110\video_ts_file\decode.bat
		cmd := exec.Command("cmd.exe", "/C", path)
		//获取path文件的文件夹路径
		cmd.Dir = filepath.Dir(path)

		cmd.Stdout = os.Stdout // 将标准输出重定向到 Go 程序的标准输出
		cmd.Stderr = os.Stderr // 将标准错误重定向到 Go 程序的标准错误

		err := cmd.Run()
		if err != nil {
			log.Println(err)
			return
		}
	}()
}

func CheckUvr5HasStop(hwnd Hwnd) {
	for {
		var intX int
		var intY int
		ret := hwnd.Dm.FindPic(0, 0, 2000, 2000, config.GetPath(`dm\bmp\uvr5_start.bmp`), "000000", 0.8, 0, &intX, &intY)
		if ret >= 0 {
			log.Println("检测到uvr5转换工作已经停止!")
			return
		}
		time.Sleep(1500 * time.Microsecond)
	}
}
